;*****************************************************************************************************
;+
; NAME:
;       IGL_PLOT
;
; PURPOSE:
;
;       This is a basic vizualisation object which represents a line
;       plot. It is subclassed from IGL_BaseRangeObject to have all
;       the necessary pan/zoom behaviour for interactivity.
;
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
; SUPERCLASSES:
;
;       IGL_BASERANGEOBJECT
;
; SYNTAX:
;
;       plot = Obj_New('IGL_Plot')
;
;
; CLASS_STRUCTURE:
;
;          class = {IGL_Plot, $
;            INHERITS IGL_BASERANGEOBJECT, $ ; This is an IGL_BASERANGEOBJECT subclass
;            xdata:ptr_new(), $              ; The independent variable to plot            
;            ydata:ptr_new(), $              ; The dependent variable  to plot
;            linestyle:0B, $                 ; The plot linestyle
;            color:'', $                     ; The name of the foreground color (line/symbols)
;            psym:0L, $                      ; The symbol integer code
;            symsize:0.0, $                  ; The symbol size
;            thick:0.0, $                    ; The thickness of the line/symbols            
;            clip:0B, $                      ; Flag indicating if the plot is clipped
;            polar:0B, $                     ; Flag indicating if the plot is a polar plot
;            visible:0B $                    ; Flag indicating if the plot is visible or not
;           }
;
;
;
; MODIFICATION_HISTORY:
;
;       Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::CONTROLPANEL
;
; PURPOSE:
;
;       This method creates a control panel for the graphic.
;
; SYNTAX:
;
;       self -> ControlPanel, baseObject
;
; ARGUMENTS:
;
;       baseObject:    The object reference of a base widget for this control to
;                      be added to. If not supplied, the control panel will be in a
;                      self contained window.
;
; KEYWORDS:
;
;       _EXTRA:       Any keywords appropriate for the CATCONTROLPANEL::INIT method.
;-
;*****************************************************************************************************
PRO IGL_Plot::ControlPanel, baseObject, _EXTRA=extraKeywords

   @cat_pro_error_handler

   ;; Create a new control panel
   cp = OBJ_NEW ('CatControlPanel', self, PARENT=baseObject, COLUMN=1, $
      TITLE='IGL_Plot Control Panel', _EXTRA=extraKeywords, /No_Cancel, /No_Apply, /No_OK)

   IF (NOT OBJ_VALID (cp)) THEN RETURN
   
   aproperties = Obj_New('PROPERTYSHEETWIDGET', cp, Value=self, Name='IGL_PLOT PROPERTYSHEET', YSize=16)
   aproperties -> SetProperty, Event_Object=self

   ;; Display the control panel if it created its own TLB.
   IF cp -> Created_Own_TLB(tlb) THEN tlb -> Draw, /Center

   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::DRAW
;
; PURPOSE:
;
;       This method draws the line plot in the current display window.
;
; SYNTAX:
;
;       self -> Draw
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       _EXTRA:     Any keyword accepted by the CATATOM::Draw method.
;
;-
;*****************************************************************************************************
PRO IGL_Plot::Draw, _Extra=extrakeywords

   @cat_pro_error_handler

   ;; If the object is invisible, then return immediately.
   IF self.visible EQ 0 THEN RETURN

   ;; Make sure the data is valid
   IF PTR_VALID(self.xdata) EQ 0 THEN RETURN
   IF PTR_VALID(self.ydata) EQ 0 THEN RETURN

   ;; Save the IDL plot variables
   cx = !x
   cy = !y
   cz = !z

   ;; Switch to decomposed color
   SetDecomposedState, 1, CURRENTSTATE=currentState
   
   ;; Apply the coordinate system.
   self -> ApplyCoords

   ;; Calculate the scale factor for the line thickness
   IF !D.name EQ 'PS' THEN factor = 2.5 ELSE factor = 1.0
 
   ; Draw the object here.
   self._coords -> GetProperty, xrange=xrange, yrange=yrange, position=position, xlog=xlog, ylog=ylog
   IF (position[0] GE position[2]) THEN return
   IF (position[1] GE position[3]) THEN return
   PLOT, *self.xdata, *self.ydata, $
         position=position, $  
         xrange=xrange, $
         yrange=yrange, $
         xlog=xlog, $
         ylog=ylog, $
         xstyle=5, $
         ystyle=5, $
         linestyle=self.linestyle, $
         color=cgcolor(self.color), $
         thick=self.thick*factor, $
         psym=symcat(self.psym,thick=self.thick*factor,color=cgcolor(self.color)), $
         symsize=self.symsize, $
         noclip=1-keyword_set(self.clip), $
         polar=self.polar, $
         /noerase
    

   ;; Restore decomposed state
   SetDecomposedState, currentState

   ;; Save the coordinate system
   !igl_x = !x
   !igl_y = !y
   !igl_z = !z

   ;; Restore the IDL plot variables
   !x = cx
   !y = cy
   !z = cz    

   ;; Draw the children
   self -> CatAtom::Draw, _EXTRA=extra    

   ;; Report completion
   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::EVENTHANDLER
;
; PURPOSE:
;
;       This method is an event handler for the Control Panel.
;
; SYNTAX:
;
;       Called automatically by the event handling system
;
; ARGUMENTS:
;
;       event:  The event structure.
;
; KEYWORDS:
;
;       None.
;-
;*****************************************************************************************************
PRO IGL_Plot::EventHandler, event

   @cat_pro_error_handler

   ; Get the name of the widget generating the event. Branch on this.
   event.ID -> GetProperty, Name=eventName
   
   CASE eventName OF

      'IGL_PLOT PROPERTYSHEET': BEGIN

         IF event.type EQ 0 THEN BEGIN
            
            CASE StrUpCase(event.identifier) OF

               'COLOR': BEGIN

                  event.component -> GetProperty, Color=color
                  event.id -> GetProperty, ID=group_leader
                  color = PickColorName(color, Group_Leader=group_leader)
                  event.component -> SetProperty, Color=color

                  ;; Refresh graphic hierarchy
                  IGL_RefreshDraw, event.component, /Buffered_Output
                  

               END

               ELSE: BEGIN

                  component = event.component
                  identifier = event.identifier
                  event.id -> GetProperty, Value=value, Component=component, Property_Value=identifier
                  event.component -> SetPropertyByIdentifier, identifier, value

                  ;; Refresh graphic hierarchy
                  IF OBJ_VALID(event.component) THEN IGL_RefreshDraw, event.component, /Buffered_Output

               END

            ENDCASE

         ENDIF ; of BUTTON DOWN EVENT

         END

        ; If you can't handle the event here. Pass it along to superclass EventHandler
        ELSE: self -> IGL_BASERANGEOBJECT::EventHandler, event

   ENDCASE

   ;; Report completion
   IF Obj_Valid(self) THEN self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::GETPROPERTY
;
; PURPOSE:
;
;       This method is used to get the object's properties.
;
; SYNTAX:
;
;       self -> GetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     LINESTYLE: The linestyle integer code of the plot. 
;
;     THICK:     The thickness of the plot.
;
;     PSYM:      The symbol integer code.
;
;     SYMSIZE:   The symbol size.
;
;     COLOR:     The name of the plot color.
;
;     CLIP:      The clipping state of the line plot.
;
;     POLAR:     The flag indicating if the plot is a polar plot.
;
;     VISIBLE:   The flag indicating if the plot is visible.
;
;     _REF_EXTRA:     Any keywords appropriate for the superclass GetProperty method.
;-
;*****************************************************************************************************
PRO IGL_Plot::GetProperty, XDATA=xdata, $
                           YDATA=ydata, $
                           LINESTYLE=linestyle, $
                           THICK=thick, $
                           PSYM=psym, $
                           SYMSIZE=symsize, $
                           CLIP=clip, $
                           COLOR=color, $
                           POLAR=polar, $
                           VISIBLE=visible, $
                           _REF_EXTRA=extraKeywords

   @cat_pro_error_handler


   IF (arg_present(xdata)) THEN IF PTR_VALID(self.xdata) THEN xdata = *self.xdata
   IF (arg_present(ydata)) THEN IF PTR_VALID(self.ydata) THEN ydata = *self.ydata
   IF (arg_present(linestyle)) THEN linestyle = self.linestyle
   IF (arg_present(color)) THEN color = self.color
   IF (arg_present(thick)) THEN thick = self.thick
   IF (arg_present(psym)) THEN psym = self.psym
   IF (arg_present(symsize)) THEN symsize = self.symsize
   IF (arg_present(polar)) THEN polar = self.polar
   IF (arg_present(visible)) THEN visible = self.visible
   IF (arg_present(clip)) THEN clip = self.clip

   IF (N_ELEMENTS (extraKeywords) GT 0) THEN self -> IGL_BASERANGEOBJECT::GetProperty, _EXTRA=extraKeywords

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::SETPROPERTY
;
; PURPOSE:
;
;       This method is used to set the object's properties.
;
; SYNTAX:
;
;       self -> SetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     LINESTYLE: The linestyle integer code of the plot. 
;
;     THICK:     The thickness of the plot.
;
;     PSYM:      The symbol integer code.
;
;     SYMSIZE:   The symbol size.
;
;     COLOR:     The name of the plot color.
;
;     CLIP:      Set this keyword if you want to have plot clipped at
;                the edge of the plot window.
;
;     POLAR:     Set this keyword to indicate that the object represents a
;                polar plot.
;
;     VISIBLE:   Set this keyword to make the plot visible or not.
;
;     _EXTRA:    Any keyword accepted by the SetProperty method of
;                the IGL_BASERANGEOBJECT superclass.
;-
;*****************************************************************************************************
PRO IGL_Plot::SetProperty, LINESTYLE=linestyle, $
                           CLIP=clip, $
                           COLOR=color, $
                           THICK=thick, $
                           PSYM=psym, $
                           SYMSIZE=symsize, $
                           VISIBLE=visible, $
                           _EXTRA=extraKeywords

   @cat_pro_error_handler
   
   IF (n_elements(linestyle) NE 0) THEN self.linestyle = 0 > linestyle < 6
   IF (n_elements(thick) NE 0) THEN self.thick = 1 > thick
   IF (n_elements(psym) NE 0) THEN self.psym = 0 > psym < 46
   IF (n_elements(symsize) NE 0) THEN self.symsize = 0.1 > symsize   
   IF (n_elements(visible) NE 0) THEN self.visible = keyword_set(visible)
   IF (n_elements(clip) NE 0) THEN self.clip = keyword_set(clip)
   
   IF (n_elements(color) NE 0) THEN BEGIN
      self.color = color
      self -> SetPropertyAttribute, 'COLOR', USERDEF=CapFirstLetter(self.color)
      IF Obj_Valid(self._controlpanel) THEN self._controlpanel -> Refresh_Properties, Properties='COLOR'
   ENDIF

   self -> IGL_BASERANGEOBJECT::SetProperty, _EXTRA=extraKeywords

   ;; Report completion
   IF OBJ_VALID(self) THEN self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::CLEANUP
;
; PURPOSE:
;
;       This is the IGL_Plot object class destructor method.
;
; SYNTAX:
;
;       Called automatically when the object is destroyed.
;
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     None.
;-
;*****************************************************************************************************
PRO IGL_Plot::CLEANUP

   @cat_pro_error_handler

   PTR_FREE, self.xdata
   PTR_FREE, self.ydata
   
   self -> IGL_BASERANGEOBJECT::CLEANUP

   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Plot::INIT
;
; PURPOSE:
;
;       This is the IGL_Plot object class creator method.
;
; SYNTAX:
;
;       Called automatically when the object is created.
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     XDATA:     The independent variable of the plot. If it is not
;                provided, it is set to FINDGEN(N_ELEMENTS(YDATA))
;
;     YDATA:     The dependent variable of the plot. If it is not
;                provided, it is set to [0,1].
;
;     LINESTYLE: The linestyle integer code of the plot. 
;
;     THICK:     The thickness of the plot.
;
;     PSYM:      The symbol integer code.
;
;     SYMSIZE:   The symbol size.
;
;     COLOR:     The name of the plot color.
;
;     CLIP:      Set this keyword if you want to have plot clipped at
;                the edge of the plot window.
;
;     POLAR:     Set this keyword to indicate that the object represents a
;                polar plot.
;
;     _EXTRA:    Any keywords accepted by the IGL_BASERANGEOBJECT::Init method.
;
;-
;*****************************************************************************************************
FUNCTION IGL_Plot::INIT, XDATA=xdata, $
                         YDATA=ydata, $
                         LINESTYLE=linestyle, $
                         THICK=thick, $
                         PSYM=psym, $
                         SYMSIZE=symsize, $
                         POLAR=polar, $
                         COLOR=color, $
                         CLIP=clip, $
                         _EXTRA=extraKeywords

   ; Set up error handler and call superclass INIT method
   @cat_func_error_handler

   ;; Initialize the global system variables
   IGL_InitSysVars

   ;; Default keyword values
   IF (n_elements(ydata) EQ 0) THEN ydata = [0,1]
   IF (n_elements(xdata) EQ 0) THEN xdata = findgen(n_elements(ydata))
   IF (n_elements(linestyle) EQ 0) THEN linestyle = !IGL_P.linestyle
   IF (n_elements(color) EQ 0) THEN color = !IGL_P.color
   IF (n_elements(thick) EQ 0) THEN thick = (!IGL_P.thick EQ 0) ? 1 : !IGL_P.thick
   IF (n_elements(psym) EQ 0) THEN psym = !IGL_P.psym
   IF (n_elements(symsize) EQ 0) THEN symsize = (!IGL_P.symsize EQ 0) ? 1 : !IGL_P.symsize
   IF (n_elements(clip) EQ 0) THEN clip = 1-keyword_set(!IGL_P.noclip)

   ;; Initialize the superclasses
   ok = self -> IGL_BASERANGEOBJECT::Init(NAME='Plot', $
                                          DESCRIPTION='Line Plot', $
                                          _EXTRA=extraKeywords)
   
   IF (NOT ok) THEN RETURN, 0


   ; Load object.
   self.xdata = ptr_new(xdata,/allocate_heap)
   self.ydata = ptr_new(ydata,/allocate_heap)
   self.linestyle = 0 > linestyle < 6
   self.thick = 1 > thick
   self.psym = 0 > psym < 46
   self.symsize = 0.1 > symsize
   self.color = color
   self.clip = keyword_set(clip)
   self.polar = keyword_set(polar)
   self.visible = 1

   ; Register properties for the property sheet.
   self -> SetPropertyAttribute, 'NAME', sensitive=0
   self -> SetPropertyAttribute, 'DESCRIPTION', sensitive=0
   self -> RegisterProperty, 'CLIP', /Boolean, name='Clipping'
   self -> RegisterProperty, 'COLOR', 0, name='Color', userdef=CapFirstLetter(self.color)
   self -> RegisterProperty, 'LINESTYLE', /Linestyle, name='Line Style'
   self -> RegisterProperty, 'PSYM', name='Symbol', enumList=IGL_GetSymbolList()
   self -> RegisterProperty, 'SYMSIZE', /float, name='Symbol Size', valid_range=[0.1,10.0]
   self -> RegisterProperty, 'THICK', /integer, name='Thickness', valid_range=[1,10]

   ;; Report completion
   self -> Report, /Completed

   RETURN, 1

END


;*****************************************************************************************************
;
; NAME:
;       IGL_PLOT CLASS DEFINITION
;
; PURPOSE:
;
;       This is the IGL_Plot object's structure definition code.
;
;*****************************************************************************************************
PRO IGL_Plot__Define, class

  COMPILE_OPT idl2, HIDDEN

   class = {IGL_Plot, $
            INHERITS IGL_BASERANGEOBJECT, $ ; This is an IGL_BASERANGEOBJECT subclass
            xdata:ptr_new(), $              ; The independent variable to plot            
            ydata:ptr_new(), $              ; The dependent variable  to plot
            linestyle:0B, $                 ; The plot linestyle
            color:'', $                     ; The name of the foreground color (line/symbols)
            psym:0L, $                      ; The symbol integer code
            symsize:0.0, $                  ; The symbol size
            thick:0.0, $                    ; The thickness of the line/symbols            
            clip:0B, $                      ; Flag indicating if the plot is clipped
            polar:0B, $                     ; Flag indicating if the plot is a polar plot
            visible:0B $                    ; Flag indicating if the plot is visible or not
           }

   struct_hide, class

END

